package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.TeachPlanEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.convert.TeachplanConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.Teachplan;
import com.xuecheng.content.entity.TeachplanMedia;
import com.xuecheng.content.entity.node.TeachplanNode;
import com.xuecheng.content.mapper.TeachplanMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.TeachplanMediaService;
import com.xuecheng.content.service.TeachplanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 课程计划 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class TeachplanServiceImpl extends ServiceImpl<TeachplanMapper, Teachplan> implements TeachplanService {


    @Autowired
    private CourseBaseService courseBaseService;

    @Autowired
    private TeachplanMediaService teachplanMediaService;

    /* 业务分析 查询课程计划
        关键数据 courseBaseId companyId 不为空
        业务数据 -- 查询课程计划的课程基本信息 不为空
        为空报异常，不为空，
        在查询课程计划，
        递归，将查询的数据转为树状结构，并不返回一级目录，从二级开始返回
        PO-->DTO 返回
        返回值-树状结构
     */
    public TeachplanDTO queryTeachPlanById(Long courseBaseId, Long companyId) {
        // 关键数据 courseBaseId companyId 不为空
        if (ObjectUtils.isEmpty(courseBaseId)) {
            ExceptionCast.cast(ContentErrorCode.E_120020);
        }

        ExceptionCast.cast(ObjectUtils.isEmpty(companyId), ContentErrorCode.E_120021);

        //业务数据 -- 查询课程计划的课程基本信息 不为空，并且是同一家机构
        CourseBase courseBase = getCourseBase(courseBaseId, companyId);
        ExceptionCast.cast(ObjectUtils.isEmpty(courseBase),ContentErrorCode.E_120013);

        // 判断课程是否被删除
        Integer status = courseBase.getStatus();
        ExceptionCast.cast(CommonEnum.DELETE_FLAG.getCodeInt().equals(status),ContentErrorCode.E_120022);

        //递归，将查询的数据转为树状结构，并不返回一级目录，从二级开始返回
        TeachplanMapper teachplanMapper = this.getBaseMapper();
        List<TeachplanNode> nodes = teachplanMapper.selectByCourseIdAll(courseBaseId);

        TeachplanDTO resultDTO = null;

        if (CollectionUtils.isEmpty(nodes)) {
            resultDTO = new TeachplanDTO();
            //返回值-树状结构

        }else {
            //排序查询所得数据中 -- 判断 根目录是否存在 -- 不存在报错
            TeachplanNode teachplanNode = nodes.remove(0);


            //递归
            recursionTeachPlan(teachplanNode, nodes);

            //在查询课程计划，PO-->DTO 返回

            resultDTO = TeachplanConvert.INSTANCE.node2dto(teachplanNode);
            //返回值-树状结构

        }
        return resultDTO;


    }


    //递归 将集合转为树桩结构(一级包含二级，二级包含三级)
    private void recursionTeachPlan(TeachplanNode rootNode, List<TeachplanNode> nodes) {

         //树桩结构 开头为根目录，二级、三级为根目录下的子级
        // 判断父级的集合是否为空，为空则需要创建出集合对象
        if (ObjectUtils.isEmpty(rootNode.getChildrenNodes())) {
            rootNode.setChildrenNodes(new ArrayList<>());
        }

        //遍历集合进行分组，让每个三级目录对应二级目录
        for (TeachplanNode node : nodes) {

            //当node中的ParentId = 根目录的ID 说明是二级目录
            if (ObjectUtils.nullSafeEquals(rootNode.getId(),node.getParentid())) {
                // 先二级目录 添加到一级目录的集合中
                rootNode.getChildrenNodes().add(node);
                //判断Grade的值是否等于 3，等于3 为三级目录
                if (!(TeachPlanEnum.THIRD_LEVEL.equals(node.getGrade()))) {
                    //若为二级 则遍历集合 将 三级目录加入到二级目录的集合中
                    recursionTeachPlan(node,nodes);
                }
            }
        }
    }



    /* 需求分析
        获取父节点ID(Parentid)若为空 说明第一次创建二级 先创建一级
        关键数据 teachplanDTO --不为空
        业务数据
            查看课程基本信息，不存在不能创建课程计划，审核状态在已提交与审核中不可修改
            查看是否存在根目录 不存在创建，存入二级、三级目录
            根据 课程计划ID判断是新增还是修改
        返回数据
            将新增或修改的后的 PO-->DTO，并返回
     */
    public TeachplanDTO createOrModifyTeachPlan(TeachplanDTO teachplanDTO,Long companyId) {
        //关键数据 teachplanDTO --不为空
        ExceptionCast.cast(ObjectUtils.isEmpty(teachplanDTO),ContentErrorCode.E_120415);


        TeachplanDTO resutlDTO = null;
        //判断 课程计划ID 是否为空 为空新建 不为空修改
        if (ObjectUtils.isEmpty(teachplanDTO.getTeachPlanId())) {
            resutlDTO= createteachplan(teachplanDTO,companyId);
        }else {
            //存在修改
            resutlDTO= modifyteachplan(teachplanDTO,companyId);

        }

        //返回数据 DTO
        return teachplanDTO;
    }


    // 不存在课程计划，创建，并存入二级、三级目录
    private TeachplanDTO createteachplan(TeachplanDTO dto,Long companyId) {

        //判断关键数据
        if ( StringUtil.isBlank(dto.getPname())||
                ObjectUtils.isEmpty(dto.getCourseId())
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }


        //     课程基础信息
        //         判断是否存在
        //         判断是否是同一家机构
        //         判断是否删除
        //         判断课程的审核状态：未提交、审核未通过
        CourseBase courseBase = veriyCourseMsg(dto, companyId);


        // 3.获得当前课程计划的父级数据
        Teachplan parentNode = getParentNode(dto, courseBase);

        //  获得父级的id值给当前的课程计划赋值为parentid
        Long parentId = parentNode.getId();
        dto.setParentid(parentId);

        //在父级的等级基础上+1 获得当前课程计划的等级
        dto.setGrade(parentNode.getGrade()+1);

        //     获得当前课程计划的orderby 排序字段
        //  排序字段的值为 父级数据 中 子级数据的个数 + 1
        LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Teachplan::getParentid, parentId);
        int count = this.count(queryWrapper);
        dto.setOrderby(count+1);

        // 4.保存课程计划数据并返回保存后的结果
        Teachplan teachplan = TeachplanConvert.INSTANCE.dto2entity(dto);

        boolean result = this.save(teachplan);

        //     判断保存后的结果
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120407);
        }
        // 5.将保存后的po数据转为dto数据
        TeachplanDTO resultDTO = TeachplanConvert.INSTANCE.entity2dto(teachplan);

        return resultDTO;
    }


    //获得一个课程计划的父级数据
    private Teachplan getParentNode(TeachplanDTO dto, CourseBase courseBase) {

        // 获取父级ID 进行判断(新增为创建所以 不存在父级ID二级，存在就父级等级+1)
        Long parentid = dto.getParentid();
        if (ObjectUtils.isEmpty(parentid)) {
            //不存在添加二级
            //需要创建一个一级课程
            // 获得一个课程一级课程计划
            // courseBaseId  + 课程计划等级1  + parentId：0
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getCourseId, courseBase.getId());
            queryWrapper.eq(Teachplan::getGrade, TeachPlanEnum.FIRST_LEVEL);
            queryWrapper.eq(Teachplan::getParentid, TeachPlanEnum.FIRST_PARENTID_FLAG);

            Teachplan rootNode = this.getOne(queryWrapper);

            //根据某一个课程一级计划创建一个新的一级计划
            if (ObjectUtils.isEmpty(rootNode)) {
                // 创建一级课程计划数据
                rootNode = new Teachplan();

                rootNode.setPname(courseBase.getName());
                rootNode.setParentid(new Long(TeachPlanEnum.FIRST_PARENTID_FLAG.toString()));
                rootNode.setGrade(TeachPlanEnum.FIRST_LEVEL);
                rootNode.setDescription(courseBase.getDescription());
                rootNode.setOrderby(TeachPlanEnum.FIRST_LEVEL);
                rootNode.setCourseId(courseBase.getId());

                boolean result = this.save(rootNode);

                ExceptionCast.cast(!result,ContentErrorCode.E_120407);
            }

            return rootNode;
        }else {
            // 如果添加课程计划有parentid：三级课程计划

            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();

            queryWrapper.eq(Teachplan::getId, parentid);

            Teachplan secNode = this.getOne(queryWrapper);

            ExceptionCast.cast(ObjectUtils.isEmpty(secNode),ContentErrorCode.E_120408);

            return secNode;
        }

    }

    // 存在课程计划，修改课程计划
    private TeachplanDTO modifyteachplan(TeachplanDTO dto,Long companyId) {

        //判断关键数据不为空
        if (StringUtil.isBlank(dto.getPname())||
                ObjectUtils.isEmpty(dto.getCourseId())||
                ObjectUtils.isEmpty(dto.getParentid())||
                ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        //判断修改的信息是否存在 是否是同一家机构的
        veriyCourseMsg(dto, companyId);


        //获取分级ID 判断父级是否存在 parentid
        Long parentid = dto.getParentid();
        Teachplan teachplan = this.getById(parentid);
        ExceptionCast.cast(ObjectUtils.isEmpty(teachplan),ContentErrorCode.E_120408);


        //  3.修改课程计划数据
        //       不允许修改的数据内容：
        //           parentid
        //           grade
        //           orderBy
        //           courseId
        Teachplan po = TeachplanConvert.INSTANCE.dto2entity(dto);

        //添加父级ID
        po.setParentid(teachplan.getParentid());
        //添加分级 父级分级+1
        po.setGrade(teachplan.getGrade());
        //添加课程ID
        po.setCourseId(teachplan.getCourseId());
        //添加排序信息
         po.setOrderby(teachplan.getOrderby());
        //  4.修改数据并判断修改后的结果
        boolean result = this.updateById(po);

        if (!result){
            ExceptionCast.cast(ContentErrorCode.E_120416);
        }

        TeachplanDTO teachplanDTO = TeachplanConvert.INSTANCE.entity2dto(po);

        return teachplanDTO;
    }




    //根据ID与机构ID查询课程信息
    private CourseBase getCourseBase(Long courseBaseId, Long companyId) {
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(CourseBase::getId, courseBaseId);
        queryWrapper.eq(CourseBase::getCompanyId, companyId);

        CourseBase courseBase = courseBaseService.getOne(queryWrapper);
        return courseBase;
    }

    //课程基础信息判断---是否同一机构 审核状态 是否删除
    private CourseBase veriyCourseMsg(TeachplanDTO dto, Long companyId) {
        CourseBase courseBase = getCourseBase(dto.getCourseId(), companyId);
        //  判断是否存在 判断是否是同一家机构
        ExceptionCast.cast(ObjectUtils.isEmpty(courseBase),ContentErrorCode.E_120013);


        // 判断是否删除
        ExceptionCast.cast(CommonEnum.DELETE_FLAG.getCode().equals(courseBase.getStatus()),
                ContentErrorCode.E_120019);

        // 判断课程的审核状态：未提交、审核未通过
        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120015);
        }
        return courseBase;
    }




    /*业务分析  删除课程计划
       关键数据 课程计划ID 不为空
       根据课程计划ID 查询
       若为二级 需查询子级 有子级存在不可删除
       若为三级 需查询是否关联了其他数据 如视频等 关联了不可删除
       返回值 Boolean
    */
    public Boolean removeTeachPlan(Long teachPlanId) {
        boolean b =false;
        //课程ID 不为空
        ExceptionCast.cast(ObjectUtils.isEmpty(teachPlanId),ContentErrorCode.E_120419);

        //根据课程计划ID 查询
        Teachplan teachplan = this.getById(teachPlanId);
        ExceptionCast.cast(ObjectUtils.isEmpty(teachplan),ContentErrorCode.E_120402);

        Integer grade = teachplan.getGrade();
        //是二级还是三级
        if (TeachPlanEnum.SECEND_LEVEL.equals(grade)){
            //grade=2 是二级
            //判断是否有子级
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid,teachplan.getId());
            List<Teachplan> list = this.list(queryWrapper);
            if (ObjectUtils.isEmpty(list)){
                //为空不存在子级 可删除
                b = this.removeById(teachPlanId);
                ExceptionCast.cast(ObjectUtils.isEmpty(b),ContentErrorCode.E_120420);

            }else {
                //不为空 说明存在子级不可删除
                ExceptionCast.cast(ContentErrorCode.E_120421);

            }
        }
        if (TeachPlanEnum.THIRD_LEVEL.equals(grade)){
            //grade=3 是三级
            //判断是否关联其他资源 查询课程计划媒体表？
            List<TeachplanMedia> mediaList = teachplanMediaService.getTeachPlanMedia(teachplan.getCourseId(), teachplan.getId());
            if (ObjectUtils.isEmpty(mediaList)){
                //为空 说明未绑定媒体资源可删除
                b = this.removeById(teachPlanId);
                ExceptionCast.cast(ObjectUtils.isEmpty(b),ContentErrorCode.E_120420);

            }else {
                //不为空 说明绑定媒体资源 不可删除
                ExceptionCast.cast(ContentErrorCode.E_120422);
            }
        }

        return b;
    }

    /*业务分析  查询课程计划
       关键数据 课程计划ID 不为空
       根据课程计划ID 查询
       判断 课程计划是否存在  是否删除
       返回值 TeachplanDTO
    */
    public TeachplanDTO getTeachPlan(Long teachPlanId) {
        //课程计划ID 不为空
        if (ObjectUtils.isEmpty(teachPlanId)){
            ExceptionCast.cast(ContentErrorCode.E_120023);
        }

        //判断 课程计划是否存在  是否删除
        Teachplan teachplan = this.getById(teachPlanId);
        if (ObjectUtils.isEmpty(teachplan)||
        CommonEnum.DELETE_FLAG.getCodeInt().equals(teachplan.getStatus())){
            ExceptionCast.cast(ContentErrorCode.E_120402);
        }

        TeachplanDTO dto = TeachplanConvert.INSTANCE.entity2dto(teachplan);


        return dto;
    }


}
